package statistics

import (
	"encoding/json"
	"github.com/Unixeno/TheMoon/common/probe"
	"github.com/Unixeno/TheMoon/logging"
	"github.com/Unixeno/TheMoon/model"
	"github.com/Unixeno/TheMoon/moon/core/module"
	"github.com/Unixeno/TheMoon/planet/core/context"
	ormModel "github.com/Unixeno/TheMoon/planet/orm/model"
	"github.com/Unixeno/TheMoon/planet/orm/moon"
	"github.com/Unixeno/TheMoon/planet/orm/statistics"
)

const ModuleName = "collector"

var logger = logging.GetLogger(ModuleName)

type Collector struct {
	moonDao  map[string]*moon.Dao
	statsDao *statistics.Dao
}

func GetModule() module.Module {
	return &Collector{}
}

func (c *Collector) Init() {
	logger.Debug("init statistics")

	c.statsDao = statistics.New()
	if c.statsDao == nil {
		logger.Fatal("failed to create statistics dao")
	}

	context.RegisterModule(ModuleName)
}

func (c *Collector) Start() {
	logger.Debug("start statistics")
	go c.worker()
}

func (c *Collector) worker() {

	for {
		message, err := context.RecvMessage(ModuleName)
		if err != nil {
			logger.WithError(err).Error()
			continue
		}
		data, ok := message.Content.([]byte)
		if !ok {
			logger.Error("unknown message type")
			continue
		}
		switch message.Operation {
		case probe.OpUpdateSettings:
			c.handleSettings(message)
		case probe.OpReport:
			c.handleStats(message.MoonID, data)
		}
	}
}

func (c *Collector) handleSettings(message *model.PlanetMessage) {
	// 请求的参数是该节点的软硬件信息，响应是统计汇报频率等信息
	nodeInfo := model.NodeInfo{}
	if err := json.Unmarshal(message.Content.([]byte), &nodeInfo); err != nil {
		logger.WithError(err).Error("invalid message content")
	}

	dao := moon.New()
	dao.ID = message.MoonID
	if err := dao.UpdateMoonInfo(ormModel.MoonInfo{
		Arch:   nodeInfo.Arch,
		Cores:  nodeInfo.Cores,
		Kernel: nodeInfo.Kernel,
		CPU:    nodeInfo.CPU,
		OS:     nodeInfo.OS,
	}); err != nil {
		logger.WithError(err).Error("failed to update moon node information")
	}

	resp := message.CreateReplay()

	resp.Content, _ = json.Marshal(model.StatisticsSettings{
		Interval: 3,
	})
	if err := context.SendMessage(&resp); err != nil {
		logger.WithError(err).Error("failed to send settings")
	}
}

func (c *Collector) handleStats(moonID string, data []byte) {
	stats := model.Statistics{}
	if err := json.Unmarshal(data, &stats); err != nil {
		logger.WithError(err).Error("invalid message content")
	}
	c.statsDao.Statistics = &stats
	c.statsDao.MoonID = moonID
	if err := c.statsDao.Store(); err != nil {
		logger.WithError(err).Error("failed to store statistics data")
	}
}
